package pl.put.miasi.agents;


import java.util.List;

import org.jbox2d.common.Mat22;
import org.jbox2d.common.Vec2;
import org.jbox2d.common.XForm;

import pl.put.miasi.volleyball.Volleyball;

public class PlayerAgent implements Runnable {

	/**
	 * robot number
	 */
	protected int number;
	/**
	 * how it checks parameters
	 */
	protected int sleepiness = 50;
	/**
	 * speed of robots
	 */
	protected int speed;
	/**
	 * optional parameter
	 */
	protected int greediness;
	/**
	 * team's robots positions
	 */
	protected List<Vec2> positions;
	/**
	 * team's robots votes
	 */
	protected List<Integer> votes;
	/**
	 * 
	 */
	protected double previousBallDistance = 0;
	protected double currentBallDistance = 0;
	protected Vec2 previousBallPosition;
	protected Vec2 currentBallPosition;
	protected Vec2 previousPlayerPosition;
	protected Vec2 currentPlayerPosition;
	protected Team team;
	protected GUI gui;
	protected int vote;
	protected Vec2 playerVelocity;
	protected float armVelocity;
	
	public PlayerAgent(int number, Team team, GUI gui) {
		this.number = number;
		this.team = team;
		this.gui = gui;
	}

	@Override
	public synchronized void run() {
/*		try {
			Thread.sleep(500);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}*/
/*		try {
			this.wait(1000);
		} catch (InterruptedException e1) {
			e1.printStackTrace();
		}*/
		while (true) {
			informAboutMyPosition();
			//sleep
			try {
				Thread.sleep(sleepiness);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			getOthersPositions();
			checkBallPosition();
			voteWhoseIsBall();
			//sleep
			try {
				Thread.sleep(sleepiness);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			getOthersVotes();
			decideWhatToDo();
			gui.movePlayer(this, playerVelocity);
			gui.movePlayerArm(this, armVelocity);
		}
	}
	
	/**
	 * Decision to move taken by player based on his paremeters and situation on court
	 * @return
	 */
	protected void decideWhatToDo() {
		if (isBallApproaching() && isBallOnMySide() && myVoteHighest()) {
			//ball is approaching
			//move to it
			playerVelocity = whereToMoveRobot();
			armVelocity = whereToMoveArm();
		} else {
			//ball is receding
			//leave it
			playerVelocity = new Vec2(0.0f, 0.0f);
			armVelocity = 0.0f;
		}
	}
	
	protected boolean isBallOnMySide() {
		boolean onMySide = false;
		if (currentBallPosition.x < 0 && this.number < 3)
			onMySide = true;
		else if (currentBallPosition.x > 0 && this.number >= 3)
			onMySide = true;
		return onMySide;
	}
	
	protected boolean isBallApproaching() {
		boolean approaching = false;
		double dx2 = Math.pow((currentPlayerPosition.x - currentBallPosition.x), 2.0);
		double dy2 = Math.pow((currentPlayerPosition.y - currentBallPosition.y), 2.0);
		double distance = Math.sqrt(dx2 + dy2);
		previousBallDistance = currentBallDistance;
		currentBallDistance = (float) distance;
		if (currentBallDistance - previousBallDistance >= 0)
			approaching = false;
		else 
			approaching = true;
		return approaching;
	}
	
	protected Vec2 whereToMoveRobot() {
		float yVelocity = 0.0f;
		float xVelocity = 0.0f;
		
		if (currentBallPosition.x - currentPlayerPosition.x > 1.0f)
			xVelocity = 8.0f;
		else
			xVelocity = -8.0f;
		
		//velocity when there is no ball
		
		//set x in the way that we approach to ball
		//set y to 0
		
		//later we will set parameters for wheel engine
		
		return new Vec2(xVelocity, yVelocity);
	}
	
	protected boolean myVoteHighest() {
		int highest = 0;
		int max = -1;
		for (int i = 0; i < votes.size(); i++) {
			if (max < votes.get(i)) {
				highest = i;
				max = votes.get(i);
			}
		}
		//System.out.println(votes.size());
		if (number < 3)
			return highest == number;
		else
			return highest == number - 3;
	}
	
	protected float whereToMoveArm() {
		float angVelocity = 0.0f;

		if (currentBallPosition.x - currentPlayerPosition.x > 0)
			angVelocity = -3.0f;
		else
			angVelocity = 3.0f;
		//rotate arm, so that it is normal to ball
		
		//later we will set parameters for arm engine
		return angVelocity; 
	}
	
	protected void getOthersPositions() {
		positions = team.getPositions();
	}
	
	protected void getOthersVotes() {
		votes = team.getVotes();
	}
	
	protected void informAboutMyPosition() {
		this.currentPlayerPosition = gui.getMyPosition(this);
		team.setPosition(this, currentPlayerPosition);
	}
	
	protected void voteWhoseIsBall() {
		//set vote simply to value of distance to where is going to fall
		vote = (int) (12.0f - currentBallDistance);
		team.vote(this, vote);
	}
	
	protected void checkBallPosition() {
		this.currentBallPosition = gui.checkBall();
	}
	
}
